package org.theSeed.springDatasouceProp.pojo.prop;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.base.Preconditions;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.theSeed.base.exp.ServiceExp;
import org.theSeed.dataSource.contract.DataSourceProp;
import org.theSeed.dataSource.pojo.dto.RelDbConnectInfo;
import org.theSeed.dataSource.pojo.sysEnum.SeedSpringDataSourceType;
import org.theSeed.springBase.utils.PropUtil;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 自定义数据源核心配置
 */
@Slf4j
@Component
@ConfigurationProperties(prefix = "seed-data-source-prop")
public class SeedDataSourceProp {
    @SneakyThrows
    @PostConstruct
    public void init(){
        if (ObjectUtil.isEmpty(primary)){
            throw new ServiceExp("默认连接数据源名称配置为空");
        }
        if(CollectionUtil.isEmpty(getConnectionInfo())){
            throw new ServiceExp("数据库连接配置为空");
        }
        //加载指定数据源配置
        if (CollectionUtil.isEmpty(getConnectionInfo()))
            throw new ServiceExp("数据源连接配置信息不能为空");
        for (Item item : getConnectionInfo()) {
            item.checkParam();
        }

        Class<?> aClass = Class.forName(poolPropClass);
        if (!DataSourceProp.class.isAssignableFrom(aClass))
            throw new ServiceExp("数据池类型暂不支持："+poolPropClass);
        this.poolInfo = (DataSourceProp)(PropUtil.getConfigObj("seed-data-source-prop.pool-info-config", aClass));
        if (ObjectUtil.isNull(poolInfo)){
            this.poolInfo = (DataSourceProp)(aClass.getConstructor().newInstance());
        }

        seedSpringDataSourceTypeEnum = SeedSpringDataSourceType.getInstance(seedSpringDataSourceType);
        if (ObjectUtil.isNull(seedSpringDataSourceTypeEnum)){
            throw new ServiceExp("数据源类型不能为空");
        }
        if (seedSpringDataSourceTypeEnum.equals(SeedSpringDataSourceType.DYNAMIC) && CollectionUtil.isEmpty(getDynamicDsNameList())){
            throw new ServiceExp("动态数据源配置,dynamicDsNameList不能为空");
        }

        initBaseDataSource();
    }

    /**
     * 数据源类型
     */
    @Getter
    @Setter
    private String seedSpringDataSourceType;

    /**
     * 数据源类型枚举
     */
    @Getter
    private SeedSpringDataSourceType seedSpringDataSourceTypeEnum;

    /**
     * 数据池类型
     */
    @Getter
    @Setter
    private String poolPropClass;

    /**
     * 数据连接池配置信息
     */
    @Getter
    @Setter
    private Map<String,Object> poolInfoConfig;

    @Getter
    @Setter
    private DataSourceProp poolInfo;

    /**
     * 数据库连接
     */
    @Getter
    @Setter
    private List<Item> connectionInfo;

    /**
     * 主数据源名称
     */
    @Getter
    @Setter
    private String primary;

    /**
     * 动态数据源添加的数据源名称
     */
    @Getter
    @Setter
    private List<String> dynamicDsNameList;

    /**
     * 所有简单数据源
     */
    @Getter
    private Map<String,DataSource> dataSourceMap = Collections.synchronizedMap(new LinkedHashMap<>());

    /**
     * 所有复杂简单数据源
     */
    @Getter
    private Map<String,DataSource> dataSourceMapComplex = new ConcurrentHashMap<>();

    /**
     * 初始化数据源
     * @return
     */
    public synchronized void initBaseDataSource() {
        createDataSource();
    }

    /**
     * 创建数据源连接
     * @return
     */
    private synchronized void createDataSource(){
        if (CollectionUtil.isEmpty(dataSourceMap)){
            log.info("系统基础数据源开始初始化");
            DataSourceProp poolInfoTmp = (DataSourceProp) poolInfo;
            connectionInfo.stream()
                    .forEach(item->{
                        try {
                            dataSourceMap.put(item.getLinkName(),poolInfoTmp.createDataSource(item));
                            log.info("名称为{}简单数据源初始化成功",item.getLinkName());
                        } catch (Exception e) {
                            log.error("名称为{}简单数据源初始化失败,原因为{}",item.getLinkName(),e.getMessage());
                            throw e;
                        }
                    });
            log.info("系统基础数据源连接初始化成功");
        }
    }


    /**
     * 数据库连接配置
     */
    @Getter
    @Setter
    public static class Item extends RelDbConnectInfo {
        /**
         * 连接名称
         */
        private String linkName;

        /**
         * 参数校验
         */
        public void checkParam(){
            Preconditions.checkArgument(ObjectUtil.isNotEmpty(linkName),"数据连接名称不能为空");
        }
    }
}
